package eu.dominicum.ra.db4o.outbound;

import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Set;

import javax.resource.ResourceException;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.ManagedConnection;
import javax.resource.spi.ManagedConnectionFactory;
import javax.security.auth.Subject;

import org.apache.log4j.Logger;

public class Db4oManagedConnectionFactory implements ManagedConnectionFactory {

	private static final long serialVersionUID = 1L;
	private static Logger LOG = Logger
			.getLogger(Db4oManagedConnectionFactory.class);

	private transient PrintWriter out;

	private String serverName;
	private Integer portNumber;
	private String username;
	private String password;

	public Db4oManagedConnectionFactory() {

		LOG.info("Instantiating a Db4oManagedConnectionFactory");
	}

	/**
	 * Creates a Connection Factory instance. The Connection Factory instance is
	 * initialized with a default ConnectionManager. In the non-managed
	 * scenario, the ConnectionManager is provided by the resource adapter.
	 * 
	 * @return EIS-specific Connection Factory instance
	 * 
	 * @exception ResourceException
	 *                if the attempt to create a connection factory fails
	 */
	public Object createConnectionFactory() throws ResourceException {

		LOG.info("Creating a Connection Factory");
		Object cf = null;

		cf = new Db4oConnectionFactory(this, null);

		LOG
				.info("Connection Factory created, type= "
						+ cf.getClass().getName());
		return cf;
	}

	/**
	 * Creates a Connection Factory instance. The ConnectionFactory instance is
	 * initialized with the passed ConnectionManager. In the managed scenario,
	 * ConnectionManager is provided by the application server.
	 * 
	 * @param cxManager
	 *            ConnectionManager to be associated with created EIS connection
	 *            factory instance
	 * 
	 * @return EIS-specific Connection Factory instance
	 * 
	 * @exception ResourceException
	 *                if the attempt to create a connection factory fails
	 */
	public Object createConnectionFactory(ConnectionManager cm)
			throws ResourceException {

		LOG.info("Creating Db4o connection factory");

		Db4oConnectionFactory cf = null;
		try {
			cf = new Db4oConnectionFactory(this, cm);
		} catch (Exception e) {
			throw new ResourceException(e.getMessage());
		}
		LOG.info("Created Db4o connection factory");
		return cf;
	}

	/**
	 * ManagedConnectionFactory uses the security information (passed as
	 * Subject) and additional ConnectionRequestInfo (which is specific to
	 * ResourceAdapter and opaque to application server) to create this new
	 * connection.
	 * 
	 * @param subject
	 *            caller's security information
	 * @param cxRequestInfo
	 *            additional resource adapter specific connection request
	 *            information
	 * 
	 * @return ManagedConnection instance
	 * 
	 * @exception ResourceException
	 *                if the attempt to create a connection fails
	 */
	public ManagedConnection createManagedConnection(Subject subject,
			ConnectionRequestInfo connectionRequestInfo)
			throws ResourceException {

		LOG.info("Creating a Managed Connection");

		Db4oManagedConnection mc = null;

		mc = new Db4oManagedConnection(this, subject, connectionRequestInfo);

		LOG.info("Created a Managed Connection");
		return mc;
	}

	/**
	 * Gets the log writer for this ManagedConnectionFactory instance.
	 * 
	 * @return PrintWriter an output stream for error logging and tracing
	 * 
	 * @exception ResourceException
	 *                if the method fails
	 */
	public PrintWriter getLogWriter() throws ResourceException {

		return this.out;
	}

	/**
	 * Returns a matched managed connection from the candidate set of
	 * connections. ManagedConnectionFactory uses the security info (as in
	 * Subject) and information provided through ConnectionRequestInfo and
	 * additional Resource Adapter specific criteria to do matching. A MC that
	 * has the requested store is returned as a match
	 * 
	 * @param connectionSet
	 *            candidate connection set
	 * @param subject
	 *            caller's security information
	 * @param cxRequestInfo
	 *            additional resource adapter specific connection request
	 *            information
	 * 
	 * @return ManagedConnection if resource adapter finds an acceptable match,
	 *         otherwise null
	 * 
	 * @exception ResourceException
	 *                if the match fails
	 */
	public ManagedConnection matchManagedConnections(Set connectionSet,
			Subject subject, ConnectionRequestInfo cxRequestInfo)
			throws ResourceException {

		LOG.info("Finding a matching Managed Connection");
		Db4oManagedConnection mc = null;

		Iterator it = connectionSet.iterator();
		while (it.hasNext()) {

			Object obj = it.next();
			if (obj instanceof Db4oManagedConnection) {

				mc = (Db4oManagedConnection) obj;

				LOG.info("Found a matching Managed Connection");
			}
		}
		return mc;
	}

	/**
	 * Sets the log writer for this ManagedConnectionFactory instance. The log
	 * writer is a character output stream to which all logging and tracing
	 * messages for this ManagedConnectionfactory instance will be printed.
	 * 
	 * @param out
	 *            an output stream for error logging and tracing
	 * 
	 * @exception ResourceException
	 *                if the method fails
	 */
	public void setLogWriter(PrintWriter out) throws ResourceException {

		LOG.info("Setting the Log Writer");
		this.out = out;
	}

	public String getServerName() {
		return serverName;
	}

	public void setServerName(String serverName) {
		this.serverName = serverName;
	}

	public Integer getPortNumber() {
		return portNumber;
	}

	public void setPortNumber(Integer portNumber) {
		this.portNumber = portNumber;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

}
